package nonre.sgy.hessiananno;

import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.remoting.caucho.HessianServiceExporter;


public final class HessianBeanScanner extends ClassPathBeanDefinitionScanner {

    private BeanNameGenerator exporterBeanNameGenerator = new HessianBeanNameGenerator();
    private BeanNameGenerator beanNameGenerator = new  AnnotationBeanNameGenerator();

    private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    private BeanDefinitionRegistry registry;

    public HessianBeanScanner(BeanDefinitionRegistry registry) {
        super(registry);
        this.registry = registry;
    }
    
    
    @Override
    protected void registerDefaultFilters() {
    	//添加注解filter,findCandidateComponents会依此判断
        addIncludeFilter(new AnnotationTypeFilter(HessianService.class));
    }

    /**
     * 重写doscan方法，核心任务是仿xmL--给bean定义加入service属性&值和serviceInterface属性&值。
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        for (String basePackage : basePackages) {
        	
        	/**
        	 * findCandidateComponents会调用isCandidateComponent，
        	 * isCandidateComponent会先后判断是否属于excludeFilters和includeFilters，
        	 * 最终如果属于includeFilters则会返回。
        	 */
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver
                        .resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                
                //component名称 
                String originalBeanName = this.beanNameGenerator.generateBeanName(candidate,
                        this.registry);
                
                //生成hessian服务的名称
                String beanName = this.exporterBeanNameGenerator.generateBeanName(candidate, this.registry);
                
                ScannedGenericBeanDefinition bd = (ScannedGenericBeanDefinition) candidate;
                bd.setBeanClassName(HessianServiceExporter.class.getName());
                bd.setBeanClass(HessianServiceExporter.class);

                //添加service属性和值
                bd.getPropertyValues().add("service",new RuntimeBeanReference(originalBeanName));
                
                String[] interfaces = bd.getMetadata().getInterfaceNames();
                
                if (interfaces == null || interfaces.length == 0)
                    continue;
                @SuppressWarnings("rawtypes")
				Class interf = null;
                try {
                    interf = Class.forName(interfaces[0]);
                } catch (ClassNotFoundException e) {
                    continue;
                }
                
                //添加serviceInterface属性和值
                bd.getPropertyValues().add("serviceInterface", interf);
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate,
                      "/" +   beanName );
                definitionHolder = applyScopedProxyMode(scopeMetadata, definitionHolder,
                        this.registry);
                beanDefinitions.add(definitionHolder);
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
        if (beanDefinitions.isEmpty()) {
            System.out.println(this.getClass().getName()+": not service be scaned");
        } else {
            for (BeanDefinitionHolder holder : beanDefinitions) {
                AnnotatedBeanDefinition definition = (AnnotatedBeanDefinition) holder
                        .getBeanDefinition();
                System.out.println(this.getClass().getName()+": "+holder.getBeanName());

                System.out.println(this.getClass().getName()+": "+definition.getMetadata().getAnnotationTypes());
            }
        }

        return beanDefinitions;

    }

    public BeanDefinitionHolder applyScopedProxyMode(ScopeMetadata metadata, BeanDefinitionHolder definition,
            BeanDefinitionRegistry registry) {

        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
            return definition;
        }
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        return ScopedProxyUtils.createScopedProxy(definition, registry, proxyTargetClass);
    }

}
